package com.testcolision;

import java.io.InputStream;

import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.GL10;
import com.badlogic.gdx.graphics.Mesh;
import com.badlogic.gdx.graphics.PerspectiveCamera;
import com.badlogic.gdx.graphics.Pixmap.Format;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.Texture.TextureFilter;
import com.badlogic.gdx.graphics.g2d.ParticleEffect;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.graphics.g2d.TextureRegion;
import com.badlogic.gdx.graphics.g3d.decals.Decal;
import com.badlogic.gdx.graphics.g3d.decals.DecalBatch;
import com.badlogic.gdx.graphics.g3d.loaders.obj.ObjLoader;
import com.badlogic.gdx.math.MathUtils;
import com.badlogic.gdx.math.Matrix4;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.math.Vector3;
import com.testcolision.deprecated.ConstraintSphere;
import com.testcolision.simulation.Simulation;

public class Renderer {

	private SpriteBatch spriteBatch;

	private Mesh constraintSphereMesh;
	private Mesh wheelMesh;
	private Texture carTexture;
	private Mesh planeMesh;
	private Mesh carMesh;
	private Texture sandboxTexture;

	private Mesh bloque_1_2_mesh;
	private Mesh bloque_3_4_mesh;
	private Mesh bloque_5_6_mesh;
	private Mesh assetsMesh;
	private Mesh streetMesh;

	private ParticleEffect starfield;

	private PerspectiveCamera camera;

	private Decal shotSprite;
	private Texture shotTexture;
	private Texture backgroundTexture;
	private DecalBatch decalBatch;
	private Texture skyTexture;
	private Mesh cubeMesh;
	private Vector3 skyPos;

	public Renderer() {
		try {
			InputStream in = Gdx.files.internal("data/sphere.obj").read();
			constraintSphereMesh = ObjLoader.loadObj(in);
			constraintSphereMesh.scale(0.2f, 0.2f, 0.2f);
			in.close();

			in = Gdx.files.internal("data/car.obj").read();
			carMesh = ObjLoader.loadObj(in, true);
			carMesh.scale(0.3f, 0.3f, 0.3f);
			in.close();

			in = Gdx.files.internal("data/cube.obj").read();
			cubeMesh = ObjLoader.loadObj(in, true);
			cubeMesh.scale(50f, 50f, 50f);
			in.close();

			in = Gdx.files.internal("data/wheel.obj").read();
			wheelMesh = ObjLoader.loadObj(in, true);
			wheelMesh.scale(0.3f, 0.3f, 0.3f);
			in.close();

			in = Gdx.files.internal("data/maps/zona_colon_olmos_map_1.obj").read();
			bloque_1_2_mesh = ObjLoader.loadObj(in, true);
			in.close();

			in = Gdx.files.internal("data/maps/zona_colon_olmos_map_2.obj").read();
			bloque_3_4_mesh = ObjLoader.loadObj(in, true);
			in.close();

			in = Gdx.files.internal("data/maps/zona_colon_olmos_map_5_6.obj").read();
			bloque_5_6_mesh = ObjLoader.loadObj(in);
			in.close();

			in = Gdx.files.internal("data/maps/zona_colon_olmos_map_assets.obj").read();
			assetsMesh = ObjLoader.loadObj(in, true);
			in.close();

			in = Gdx.files.internal("data/maps/zona_colon_olmos_map_street.obj").read();
			streetMesh = ObjLoader.loadObj(in, true);
			in.close();

			starfield = new ParticleEffect();
			starfield.load(Gdx.files.internal("data/starfield"), Gdx.files.internal("data"));
			starfield.setPosition(Gdx.graphics.getWidth() / 2, Gdx.graphics.getHeight() / 2);
			starfield.start();

			sandboxTexture = new Texture(Gdx.files.internal("data/city_texture.png"), Format.RGBA4444, true);
			sandboxTexture.setFilter(TextureFilter.MipMap, TextureFilter.MipMap);

			skyTexture = new Texture(Gdx.files.internal("data/cubemap.png"), Format.RGB565, false);
			skyTexture.setFilter(TextureFilter.Linear, TextureFilter.Linear);

			backgroundTexture = new Texture(Gdx.files.internal("data/planet.jpg"), Format.RGB565, true);
			backgroundTexture.setFilter(TextureFilter.MipMap, TextureFilter.Linear);

			carTexture = new Texture(Gdx.files.internal("data/car.png"), Format.RGB565, true);
			carTexture.setFilter(TextureFilter.Linear, TextureFilter.Linear);

			Texture shotTexture = new Texture(Gdx.files.internal("data/shot3.png"));
			shotSprite = Decal.newDecal(0.5f, 0.5f, new TextureRegion(shotTexture), true);

			spriteBatch = new SpriteBatch();
			decalBatch = new DecalBatch();

			camera = new PerspectiveCamera(67, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
			camera.far = 1000;
			skyPos = new Vector3().set(0, 0, 0);

			GL10 gl = Gdx.graphics.getGL10();
			gl.glDisable(GL10.GL_DITHER);
			gl.glEnable(GL10.GL_DEPTH_TEST);

			// gl.glDisable(GL10.GL_LIGHTING);
			// gl.glDisable(GL10.GL_LIGHT0);
			// gl.glDisable(GL10.GL_COLOR_MATERIAL);
			// gl.glPolygonMode(gl.GL_FRONT_AND_BACK, gl.GL_LINE);
		} catch (Exception ex) {
			ex.printStackTrace();
		}
	}

	public void render(Simulation simulation, float delta) {

		GL10 gl = Gdx.graphics.getGL10();
		gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
		gl.glViewport(0, 0, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());

		setProjectionAndCamera(gl, simulation.car.m_position);

		gl.glEnable(GL10.GL_TEXTURE_2D);
		gl.glDisable(GL10.GL_DEPTH_TEST);
		// renderSkybox(gl, simulation.car);

		gl.glEnable(GL10.GL_DEPTH_TEST);
		gl.glEnable(GL10.GL_CULL_FACE);
		gl.glCullFace(GL10.GL_BACK);

		// renderBackground(delta);

		// setLighting(gl, true);
		renderCar(gl, simulation.car.m_position, simulation.car.m_angle);
		// renderWheels(gl, simulation.wheels, simulation.car);
		// renderConstraintSpheres(gl, simulation.carWheel);
		renderScene(gl);
		gl.glEnable(GL10.GL_BLEND);
		gl.glBlendFunc(GL10.GL_ALPHA, GL10.GL_SRC_ALPHA);
		gl.glDisable(GL10.GL_CULL_FACE);
		// renderAssets(gl);

	}

	private void renderAssets(GL10 gl) {
		gl.glPushMatrix();
		assetsMesh.render(GL10.GL_TRIANGLES);
		gl.glPopMatrix();
	}

	// private void renderSkybox(GL10 gl, Car car) {
	// skyTexture.bind();
	// gl.glPushMatrix();
	//
	// gl.glTranslatef(car.pos.x, car.pos.y, car.pos.z);
	//
	// cubeMesh.render(GL10.GL_TRIANGLES);
	//
	// gl.glPopMatrix();
	// }
	//
	// private void renderWheels(GL10 gl, Wheel_deprecated[] wheels, Car car) {
	// for (int i = 0; i < wheels.length; i++) {
	// gl.glPushMatrix();
	// gl.glTranslatef(wheels[i].pos.x, wheels[i].pos.y, wheels[i].pos.z);
	//
	// if (i < 2)
	// gl.glRotatef(car.angle * 3, car.upVec.x, car.upVec.y, car.upVec.z);
	// gl.glMultMatrixf(wheels[i].rotationMatrix.val, 0);
	// gl.glMultMatrixf(wheels[i].orientationMatrix.val, 0);
	// wheelMesh.render(GL10.GL_TRIANGLES);
	// gl.glPopMatrix();
	// }
	// }
	Matrix4 rotationMatrix = new Matrix4();

	private void renderCar(GL10 gl, Vector2 position, float carAngle) {
		gl.glPushMatrix();
		carTexture.bind();

		gl.glTranslatef(position.x, 0, position.y);
		gl.glRotatef(-carAngle*MathUtils.radiansToDegrees, 0, 1, 0);
		// gl.glMultMatrixf(car.orientationMatrix.val, 0);
		carMesh.render(GL10.GL_TRIANGLES);
		gl.glPopMatrix();
	}

	private void renderConstraintSpheres(GL10 gl, ConstraintSphere[] carWheel) {

		for (int i = 0; i < carWheel.length; i++) {

			gl.glPushMatrix();

			gl.glRotatef(-carWheel[i].angle, 0, 1, 0);
			constraintSphereMesh.render(GL10.GL_TRIANGLES);
			gl.glPopMatrix();
		}

	}

	private void renderBackground(float delta) {
		spriteBatch.getProjectionMatrix().setToOrtho2D(0, 0, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
		spriteBatch.begin();
		spriteBatch.disableBlending();
		spriteBatch.setColor(Color.WHITE);
		spriteBatch.draw(backgroundTexture, 0, 0, 480, 320, 0, 0, 512, 512, false, false);
		starfield.draw(spriteBatch, delta);
		spriteBatch.end();
	}

	private void renderScene(GL10 gl) {

		sandboxTexture.bind();
		gl.glPushMatrix();
		bloque_1_2_mesh.render(GL10.GL_TRIANGLES);

		bloque_3_4_mesh.render(GL10.GL_TRIANGLES);

		bloque_5_6_mesh.render(GL10.GL_TRIANGLES);

		streetMesh.render(GL10.GL_TRIANGLES);
		gl.glPopMatrix();
	}

	private void setProjectionAndCamera(GL10 gl, Vector2 position) {

		// camera.position.add(camera3D.upVec.tmp().nor().mul(2));

		camera.position.set(position.x, 0, position.y);
		camera.position.add(0, 1, 4);
		camera.lookAt(position.x, 0, position.y);
		camera.update();
		camera.apply(gl);
		// camera.direction.set(0, 0, 0).sub(camera.position).nor();
	}

	float[] direction = { 1, 0.5f, 0, 0 };

	private void setLighting(GL10 gl, boolean enabled) {
		if (enabled) {
			gl.glEnable(GL10.GL_LIGHTING);
			gl.glEnable(GL10.GL_LIGHT0);
			gl.glLightfv(GL10.GL_LIGHT0, GL10.GL_POSITION, direction, 0);
			gl.glEnable(GL10.GL_COLOR_MATERIAL);
		} else {
			gl.glDisable(GL10.GL_LIGHTING);
			gl.glDisable(GL10.GL_LIGHT0);
			gl.glDisable(GL10.GL_COLOR_MATERIAL);
		}
	}

	public void dispose() {
		constraintSphereMesh.dispose();
		carTexture.dispose();
		planeMesh.dispose();
		sandboxTexture.dispose();
		decalBatch.dispose();
		shotTexture.dispose();
		starfield.dispose();
	}

}
